#include "tcpcombase.h"

CTcpcombase::CTcpcombase()
{
}

CTcpcombase::CTcpcombase(LPST_ENV_T pEnv, struct bufferevent * pBev, int nHeadSize)
: m_pEnv(pEnv)
, m_pBev(pBev)
, m_nHeadSize(nHeadSize)
, m_nDataLen(0)
{
	bufferevent_setwatermark(pBev, EV_READ, nHeadSize, nHeadSize);
	bufferevent_setcb(pBev, CTcpcombase::cb_OnRead, CTcpcombase::cb_OnWrite, CTcpcombase::cb_OnReadWriteError, this);
	bufferevent_enable(pBev, EV_READ | EV_WRITE);
}

CTcpcombase::CTcpcombase(LPST_ENV_T pEnv, struct bufferevent * pBev, int nHeadSize, char* pHost, int nPort)
: m_pEnv(pEnv)
, m_pBev(pBev)
, m_nHeadSize(nHeadSize)
, m_nDataLen(0)
{
	bufferevent_setwatermark(pBev, EV_READ, nHeadSize, nHeadSize);
	bufferevent_setcb(pBev, CTcpcombase::cb_OnRead, CTcpcombase::cb_OnWrite, CTcpcombase::cb_OnReadWriteError, this);
	bufferevent_enable(pBev, EV_READ | EV_WRITE);
//	bufferevent_socket_connect_hostname(pBev, pEnv->pDns, AF_UNSPEC, pHost, nPort);
	struct sockaddr_in addr;
	memset(&addr, 0, sizeof(addr));
	addr.sin_family = AF_INET;
	addr.sin_port = htons(nPort);
	if (inet_pton(AF_INET, /*"119.120.92.200"*/pHost, &addr.sin_addr) <= 0){
		LOG4CPLUS_ERROR(log_dsw, "inet_pton error! err = " << strerror(errno));
		return;
	}
	bufferevent_socket_connect(pBev, (struct sockaddr *)&addr, sizeof(addr));
}

CTcpcombase::~CTcpcombase()
{
	if (m_pBev)
		bufferevent_free(m_pBev);
	LOG4CPLUS_DEBUG(log_dsw, "Destroy tcpcombase!");
}

void CTcpcombase::OnReadWriteError(struct bufferevent *bev, short events)
{
	if (events & BEV_EVENT_ERROR){
		if ((EVUTIL_SOCKET_ERROR() == EAGAIN) || (EVUTIL_SOCKET_ERROR() == EINTR)){
			LOG4CPLUS_DEBUG(log_dsw, "Low speed socket, Err = " << evutil_socket_error_to_string(EVUTIL_SOCKET_ERROR()));
			return;
		}
		else
			LOG4CPLUS_ERROR(log_dsw, "Error from bufferevent! err = " << evutil_socket_error_to_string(EVUTIL_SOCKET_ERROR())
				 << " errno = " << EVUTIL_SOCKET_ERROR());
	}
	if (events & (BEV_EVENT_EOF | BEV_EVENT_ERROR | BEV_EVENT_TIMEOUT)){
		LOG4CPLUS_ERROR(log_dsw, "Something error on socket, close it soon!");
		OnError(ERR_SOCKET, bev, events);
	}
	else if (events & BEV_EVENT_CONNECTED){
		LOG4CPLUS_DEBUG(log_dsw, "Connect server ok!");
		OnConnect(bev, events);
	}
}

void CTcpcombase::OnRead(struct bufferevent *bev)
{
	 struct evbuffer *input = bufferevent_get_input(bev);
	 int nLen = (int)evbuffer_get_length(input);
	 if ((nLen >= m_nHeadSize) && (m_nDataLen == 0)){
	 	char nData[32];
		bufferevent_read(bev, nData, m_nHeadSize);
		int nMsgLen = MakePayloadLength(nData, m_nHeadSize);
		if (nMsgLen >= MAX_TCP_RECVBUF){
			LOG4CPLUS_ERROR(log_dsw, "The data length is too large, this socket is invalid and close it soon!");
			OnError(ERR_SOCKET, bev, 0);
			return;
		}
		else{
			if (nMsgLen > 0){
				m_nDataLen = nMsgLen;
				bufferevent_setwatermark(bev, EV_READ, nMsgLen, nMsgLen);
			}
			else{
				if (!ProcessMessage(NULL, 0, bufferevent_get_output(bev))){
					LOG4CPLUS_ERROR(log_dsw, "Invalid recved data, this socket is invalid and close it soon!");
					OnError(ERR_COMM, bev, 0);
					return;
				}
				else
					bufferevent_setwatermark(bev, EV_READ, m_nHeadSize, m_nHeadSize);
			}
		}
	}
	else if ((m_nDataLen > 0) && (nLen >= m_nDataLen)){
	 	char sMsg[MAX_TCP_RECVBUF] = {0};
		bufferevent_read(bev, sMsg, m_nDataLen);
		if (!ProcessMessage(sMsg, m_nDataLen, bufferevent_get_output(bev))){
			LOG4CPLUS_ERROR(log_dsw, "Invalid recved data, this socket is invalid and close it soon!");
			OnError(ERR_COMM, bev, 0);
			return;
		}
		else
			bufferevent_setwatermark(bev, EV_READ, m_nHeadSize, m_nHeadSize);
		m_nDataLen = 0;
	 }
}

